package com.terra.ns.imp.common.dingtalk.contact.service;

import cn.hutool.core.collection.CollUtil;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.taobao.api.ApiException;
import com.terra.ns.imp.common.dingtalk.contact.domain.*;
import com.terra.ns.imp.common.dingtalk.service.DingAuthService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static com.terra.ns.imp.common.dingtalk.contact.config.UrlConstant.*;

/**
 * 部门，人员管理
 */
@Service
public class ContactService {
    private static final Logger log = LoggerFactory.getLogger(ContactService.class);


    @Autowired
    private DingAuthService tokenService;

    /**
     * 部门列表
     * @return
     */
    public List<DepartmentDTO> getDepartmentList(String departmentId) {
        String accessToken = tokenService.getAccessToken();
        return this.doGetDepartmentList(departmentId, accessToken);
    }

    /**
     * 删除部门
     * @return
     */
    public void deleteDeptById(String departmentId) {
        String accessToken = tokenService.getAccessToken();
        this.doDeleteDeptById(departmentId, accessToken);
    }

    /**
     * 分页查询 用户列表
     * @param departmentId
     * @param offset
     * @param size
     * @param order
     * @return
     */
    public List<UserDTO> getSimpleUserList(Long departmentId, long offset, long size, String order) {

        String accessToken = tokenService.getAccessToken();
        return this.doGetSimpleUserList(departmentId, offset, size, order, accessToken);

    }

    /**
     * 分页查询用户数据
     * @param departmentId
     * @param offset
     * @param size
     * @return
     */
    public List<UserV2DTO> getUserList(Long departmentId, long offset, long size){
        String accessToken = tokenService.getAccessToken();
        return this.doGetUserList(departmentId, offset, size, accessToken);

    }


    /**
     * 分页查询用户数据
     * @param departmentId
     * @param offset
     * @param size
     * @return
     */
    public List<UserV2DTO> getUserListV2(Long departmentId, long offset, long size) throws ApiException {
        String accessToken = tokenService.getAccessToken();
        return this.doGetUserListV2(departmentId, offset, size, accessToken);
    }

    /**
     * 查询部门下所有用户
     * @param departmentId
     * @return
     * @throws ApiException
     */
    public List<UserV2DTO> getAllUserByDepartmentId(Long departmentId) throws ApiException {
        List<UserV2DTO> retList = new ArrayList<UserV2DTO>();
        long offset = 0;
        long size = 100;

        List<UserV2DTO> queryList = getUserListV2(departmentId,offset,size);

        retList.addAll(queryList);

        while (queryList.size() == size ){
            offset++;

            queryList = getUserListV2(departmentId,offset,size);
            retList.addAll(queryList);
        }

        return retList;

    }

    /**
     * 查询用户详情
     * @param userId
     * @return
     */
    public UserDetail getUserDetail(String userId) throws ApiException {
        String accessToken = tokenService.getAccessToken();

        return this.doGetUserDetail(userId, accessToken);
    }


    /**
     * 查询部门和用户
     * @return
     */
    public List<DepartmentUserDTO> getDepartmentWithUser(){
        List<DepartmentDTO> deptList = getDepartmentList("1");

        List<DepartmentUserDTO> retList =  deptList.stream().map(dept ->{

            DepartmentUserDTO dto = new DepartmentUserDTO();

            BeanUtils.copyProperties(dept,dto);

            try {
                List<UserV2DTO> userList = getAllUserByDepartmentId(dept.getId());
                dto.setUserList(userList);
            } catch (ApiException e) {
                e.printStackTrace();
            }

            return dto;
        }).collect(Collectors.toList());

        return retList;
    }


    public List<DepartmentTreeDTO> buildTree(List<DepartmentDTO> list){

        if(list == null || list.isEmpty()){
            return Collections.emptyList();
        }


        List<DepartmentTreeDTO> retList = new ArrayList<DepartmentTreeDTO>();

        List<DepartmentDTO> topList = list.stream().filter(it->it.getParentid().equals(1L)).collect(Collectors.toList());

        for(DepartmentDTO dept : topList){
            if(dept != null){
                DepartmentTreeDTO treeDTO = new DepartmentTreeDTO();

                BeanUtils.copyProperties(dept,treeDTO);

                retList.add(treeDTO);

                buildChildren(treeDTO,list);

            }
        }

        return retList;

    }

    private void buildChildren(DepartmentTreeDTO treeDTO, List<DepartmentDTO> list) {

        List<DepartmentDTO> childrenList = list.stream().filter(it-> it.getParentid().equals(treeDTO.getId()))
                .collect(Collectors.toList());

        for(DepartmentDTO dept : childrenList){
            DepartmentTreeDTO childDTO = new DepartmentTreeDTO();

            BeanUtils.copyProperties(dept,childDTO);

            treeDTO.getChildren().add(childDTO);

            buildChildren(childDTO,list);

        }
    }



    public List<DepartmentUserTreeDTO> buildTree2(List<DepartmentUserDTO> list){

        if(list == null || list.isEmpty()){
            return Collections.emptyList();
        }

        log.info("start build");

        List<DepartmentUserTreeDTO> retList = new ArrayList<DepartmentUserTreeDTO>();

        List<DepartmentDTO> topList = list.stream().filter(it->it.getParentid().equals(1L)).collect(Collectors.toList());

        for(DepartmentDTO dept : topList){
            if(dept != null){
                DepartmentUserTreeDTO treeDTO = new DepartmentUserTreeDTO();

                BeanUtils.copyProperties(dept,treeDTO);

                retList.add(treeDTO);

                buildChildren2(treeDTO,list);

            }
        }

        return retList;

    }

    private void buildChildren2(DepartmentUserTreeDTO treeDTO, List<DepartmentUserDTO> list) {

        List<DepartmentUserDTO> childrenList = list.stream().filter(it-> it.getParentid().equals(treeDTO.getId()))
                .collect(Collectors.toList());

        for(DepartmentUserDTO dept : childrenList){
            DepartmentUserTreeDTO childDTO = new DepartmentUserTreeDTO();

            BeanUtils.copyProperties(dept,childDTO);

            treeDTO.getChildren().add(childDTO);

            buildChildren2(childDTO,list);

        }
    }

    public DepartmentDetailDTO departmentDetail(String deptId) {
        // 获取accessToken
        String accessToken = tokenService.getAccessToken();
        return this.doDepartmentDetail(deptId, accessToken);
    }

    //实际操作方法 ---
    public List<DepartmentDTO> doGetDepartmentList(String departmentId, String accessToken) {
        DingTalkClient client = new DefaultDingTalkClient(URL_DEPARTMENT_LIST);
        OapiDepartmentListRequest request = new OapiDepartmentListRequest();
        request.setId(departmentId);
        request.setHttpMethod("GET");

        OapiDepartmentListResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            throw new RuntimeException("Failed to listDepartment: " + e.getErrMsg());
            //return ServiceResult.failure(e.getErrCode(), "Failed to listDepartment: " + e.getErrMsg());
        }
        if (!response.isSuccess()) {
            throw new RuntimeException(response.getErrmsg());
            //return ServiceResult.failure(response.getErrorCode(), response.getErrmsg());
        }

        if (CollUtil.isNotEmpty(response.getDepartment())) {
            List<DepartmentDTO> results = new ArrayList<>(response.getDepartment().size());
            for (OapiDepartmentListResponse.Department department : response.getDepartment()) {
                DepartmentDTO departmentDTO = new DepartmentDTO();
                departmentDTO.setId(department.getId());
                departmentDTO.setName(department.getName());
                departmentDTO.setCreateDeptGroup(department.getCreateDeptGroup());
                departmentDTO.setAutoAddUser(department.getAutoAddUser());
                departmentDTO.setParentid(department.getParentid());
                results.add(departmentDTO);
            }
            return results;
        }
        return Collections.emptyList();
    }

    public List<UserDTO> doGetSimpleUserList(Long departmentId, long offset, long size, String order, String accessToken) {
        DingTalkClient client = new DefaultDingTalkClient(URL_USER_SIMPLELIST);
        OapiUserSimplelistRequest request = new OapiUserSimplelistRequest();
        request.setDepartmentId(departmentId);
        request.setOffset(offset);
        request.setSize(size);
        request.setOrder(order);
        request.setHttpMethod("GET");

        OapiUserSimplelistResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            log.error("Failed to {}", URL_DEPARTMENT_LIST, e);
            throw new RuntimeException("Failed to listDepartment: " + e.getErrMsg());
            //return ServiceResult.failure(e.getErrCode(), "Failed to listDepartment: " + e.getErrMsg());
        }
        if (!response.isSuccess()) {
            throw new RuntimeException(response.getErrmsg());
            //return ServiceResult.failure(response.getErrorCode(), response.getErrmsg());
        }

        if (CollUtil.isNotEmpty(response.getUserlist())) {
            List<UserDTO> results = new ArrayList<>(response.getUserlist().size());
            for (OapiUserSimplelistResponse.Userlist userlist : response.getUserlist()) {
                UserDTO user = new UserDTO();
                user.setUserid(userlist.getUserid());
                user.setName(userlist.getName());
                results.add(user);
            }
            return results;
        }
        return Collections.emptyList();
    }

    public List<UserV2DTO> doGetUserList(Long departmentId, long offset, long size, String accessToken) {
        DingTalkClient client = new DefaultDingTalkClient(URL_USER_LIST);
        OapiUserListbypageRequest request = new OapiUserListbypageRequest();
        request.setDepartmentId(departmentId);
        request.setOffset(offset);
        request.setSize(size);
        request.setHttpMethod("GET");

        OapiUserListbypageResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            log.error("Failed to {}", URL_DEPARTMENT_LIST, e);
            throw new RuntimeException("Failed to listDepartment: " + e.getErrMsg());
            //return ServiceResult.failure(e.getErrCode(), "Failed to listDepartment: " + e.getErrMsg());
        }
        if (!response.isSuccess()) {
            throw new RuntimeException(response.getErrmsg());
            // return ServiceResult.failure(response.getErrorCode(), response.getErrmsg());
        }

        if (CollUtil.isNotEmpty(response.getUserlist())) {
            List<UserV2DTO> results = new ArrayList<>(response.getUserlist().size());
            for (OapiUserListbypageResponse.Userlist u : response.getUserlist()) {
                UserV2DTO user = new UserV2DTO();
                user.setUserid(u.getUserid());
                user.setName(u.getName());
                user.setAvatar(u.getAvatar());
                user.setUnionid(u.getUnionid());
                user.setLeader(u.getIsLeader());
                user.setMobile(u.getMobile());
                user.setActive(u.getActive());
                user.setRemark(u.getRemark());
                user.setAdmin(u.getIsAdmin());
                user.setOrgEmail(u.getOrgEmail());
                user.setJobNumber(u.getJobnumber());

                user.setBoss(u.getIsBoss());
                user.setHiredDate(u.getHiredDate());
                user.setExtattr(u.getExtattr());

                user.setPosition(u.getPosition());

                user.setDepartment(u.getDepartment());
                user.setWorkPlace(u.getWorkPlace());
                user.setEmail(u.getEmail());


                results.add(user);
            }
            return results;
        }

        return Collections.emptyList();
    }

    public List<UserV2DTO> doGetUserListV2(Long departmentId, long offset, long size, String accessToken) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient(RUL_USER_LIST_V2);
        OapiV2UserListRequest req = new OapiV2UserListRequest();
        req.setDeptId(departmentId);
        req.setCursor(offset);
        req.setSize(size);
        OapiV2UserListResponse rsp = client.execute(req, accessToken);

        if (!rsp.isSuccess()) {
            throw new RuntimeException(rsp.getErrmsg());
            //return ServiceResult.failure(rsp.getErrorCode(), rsp.getErrmsg());
        }

        List<OapiV2UserListResponse.ListUserResponse> userList = rsp.getResult().getList();

        if (CollUtil.isNotEmpty(userList)) {
            List<UserV2DTO> results = new ArrayList<>(userList.size());
            for (OapiV2UserListResponse.ListUserResponse u : userList) {
                UserV2DTO user = new UserV2DTO();
                user.setUserid(u.getUserid());
                user.setName(u.getName());
                user.setAvatar(u.getAvatar());
                user.setUnionid(u.getUnionid());
//                user.setOpenId(u.get);
                user.setLeader(u.getLeader());
                user.setMobile(u.getMobile());
                user.setActive(u.getActive());
                user.setRemark(u.getRemark());
                user.setAdmin(u.getAdmin());
                user.setOrgEmail(u.getOrgEmail());
                user.setJobNumber(u.getJobNumber());

                user.setBoss(u.getBoss());
                Date hd = null;
                if(u.getHiredDate() != null){
                    hd = new Date(u.getHiredDate());
                }
                user.setHiredDate(hd);
                user.setExtattr(u.getExtension());


                user.setDepartment(u.getDeptIdList());
                user.setWorkPlace(u.getWorkPlace());
                user.setEmail(u.getEmail());
                user.setTitle(u.getTitle());


                results.add(user);
            }
            return results;
        }
        return Collections.emptyList();
    }

    public UserDetail doGetUserDetail(String userId, String accessToken) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient(URL_USER_DETAIL);
        OapiV2UserGetRequest req = new OapiV2UserGetRequest();
        req.setUserid(userId);
        OapiV2UserGetResponse rsp = client.execute(req, accessToken);

        if (!rsp.isSuccess()) {
            throw new RuntimeException(rsp.getErrmsg());
            // return ServiceResult.failure(rsp.getErrorCode(), rsp.getErrmsg());
        }

        OapiV2UserGetResponse.UserGetResponse userInfo = rsp.getResult();

        UserDetail detail = new UserDetail();

        BeanUtils.copyProperties(userInfo, detail);

        if (userInfo.getDeptPositionList() != null) {
            List<DeptPosition> list = userInfo.getDeptPositionList().stream().map(it -> {
                DeptPosition position = new DeptPosition();
                BeanUtils.copyProperties(it, position);
                return position;
            }).collect(Collectors.toList());

            detail.setDeptPositionList(list);
        }

        if (userInfo.getLeaderInDept() != null) {
            List<DeptLeader> list = userInfo.getLeaderInDept().stream().map(it -> {
                DeptLeader leader = new DeptLeader();
                BeanUtils.copyProperties(it, leader);
                return leader;
            }).collect(Collectors.toList());

            detail.setLeaderInDept(list);
        }

        if (userInfo.getRoleList() != null) {
            List<UserRole> roleList = userInfo.getRoleList().stream().map(it -> {
                UserRole role = new UserRole();
                BeanUtils.copyProperties(it, role);
                return role;
            }).collect(Collectors.toList());

            detail.setRoleList(roleList);
        }

        return detail;
    }

    public DepartmentDetailDTO doDepartmentDetail(String deptId, String accessToken) {
        if (StringUtils.isEmpty(accessToken)) {
            log.info("departmentDetail#getAccessToken fail");
            throw new RuntimeException("getAccessToken fail");
        }
        DingTalkClient client = new DefaultDingTalkClient(URL_DEPARTMENT_DETAIL);
        OapiDepartmentGetRequest request = new OapiDepartmentGetRequest();
        request.setId(deptId);
        request.setHttpMethod("GET");

        OapiDepartmentGetResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            log.error("Failed to {}", URL_DEPARTMENT_DETAIL, e);
            return null;
        }
        if (!response.isSuccess()) {
            throw new RuntimeException(response.getErrmsg());
            // return ServiceResult.failure(rsp.getErrorCode(), rsp.getErrmsg());
        }

        DepartmentDetailDTO result = new DepartmentDetailDTO();
        BeanUtils.copyProperties(response, result);
        if (response.getAutoAddUser() != null) {
            if (response.getAutoAddUser()) {
                result.setAutoAddUser(1);
            } else {
                result.setAutoAddUser(0);
            }
        }
        if (response.getCreateDeptGroup() != null) {
            if (response.getCreateDeptGroup()) {
                result.setCreateDeptGroup(1);
            } else {
                result.setCreateDeptGroup(0);
            }
        }
        if (response.getDeptHiding() != null) {
            if (response.getDeptHiding()) {
                result.setHideDept(1);
            } else {
                result.setHideDept(0);
            }
        }
        if (response.getGroupContainSubDept() != null) {
            if (response.getDeptHiding()) {
                result.setGroupContainSubDept(1);
            } else {
                result.setGroupContainSubDept(0);
            }
        }
        if (response.getIsFromUnionOrg() != null) {
            if (response.getIsFromUnionOrg()) {
                result.setFromUnionOrg(1);
            } else {
                result.setFromUnionOrg(0);
            }
        }
        if (response.getOuterDept() != null) {
            if (response.getOuterDept()) {
                result.setOuterDept(1);
            } else {
                result.setOuterDept(0);
            }
        }
        //sourceIdentifier自行生成关联自研系统中生成的唯一编码
        return result;
    }

    public void doDeleteDeptById(String departmentId, String accessToken) {
        DingTalkClient client = new DefaultDingTalkClient(URL_DEPARTMENT_DELETE);
        OapiV2DepartmentDeleteRequest request = new OapiV2DepartmentDeleteRequest();
        request.setDeptId(Long.valueOf(departmentId));
        request.setHttpMethod("POST");

        OapiV2DepartmentDeleteResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            throw new RuntimeException("Failed to deleteDepartment: " + e.getErrMsg());
            //return ServiceResult.failure(e.getErrCode(), "Failed to listDepartment: " + e.getErrMsg());
        }
        if (!response.isSuccess()) {
            throw new RuntimeException(response.getErrmsg());
            //return ServiceResult.failure(response.getErrorCode(), response.getErrmsg());
        }
    }
}
